//
// Created by Administrator on 2024/10/21.
//

#ifndef BASE_HPP
#define BASE_HPP
#include <mutex>
#include <set>
#include <chrono>

#include "message_factory.hpp"
#include "../jtt809_logger.h"
#include "../protocol/util/constants.h"
#define TIME_TO_WAIT std::chrono::seconds(5)

namespace network {
    class Waitable {
    public:
        bool wait_for_next(const protocol::JTT809Bodies next = protocol::JTT809Bodies::ANY) {
            std::unique_lock lock(mutex_);
            next_.insert(next);
            while (!get_it_ && (next != current_ || next == protocol::JTT809Bodies::ANY)) {
                if (cond_.wait_for(lock, TIME_TO_WAIT) == std::cv_status::timeout) {
                    JTT809Logger::logger()->warn("the wait request of message type [0X{:X}] time out", static_cast<int>(next));
                    return false;
                } else {
                    JTT809Logger::logger()->debug("I am waiting");
                }
            }
            get_it_ = false;
            return true;
        }

        void get_it(const protocol::JTT809Bodies who) {
            std::lock_guard lock(mutex_);
            if (const auto found = next_.find(who); found != next_.end()) {
                current_ = *found;
                next_.erase(found);
                next_.erase(protocol::JTT809Bodies::ANY);
                get_it_ = true;
                cond_.notify_all();
            } else if (next_.contains(protocol::JTT809Bodies::ANY)) {
                current_ = protocol::JTT809Bodies::ANY;
                next_.erase(protocol::JTT809Bodies::ANY);
                get_it_ = true;
                cond_.notify_all();
            }
        }

        virtual ~Waitable() = default;

    protected:
        virtual void get_packet(std::optional<Packet> &packet) {

        }

        std::mutex mutex_;
        std::condition_variable cond_;
        std::set<protocol::JTT809Bodies> next_;
        protocol::JTT809Bodies current_ = protocol::JTT809Bodies::ANY;
        bool get_it_ = false;
    };
}

#endif //BASE_HPP
